function WebGLPiece(gl, value, radius)
{
    if(value < 1) throw "Invalid piece value";

    var corners = value + 2;
    var halfangle = Math.PI / corners;
    var triarea = radius * radius * Math.cos(halfangle) * Math.sin(halfangle) / 2.0;
    var area = corners * triarea;
    var height = radius * (5.0 + value * value) / 25.0;
    
    var numVertices = 
        2 * (corners + 1) // face outer edges
        + 2 // triangle fan centers
        + 6 * corners; // outer faces, not indexed
        // + 4 * corners; // outer faces (indexed)
        
        
    var floatsPerVertex = 6;
    
    var vertices = new WebGLFloatArray(numVertices * floatsPerVertex);

    // TODO: Figure out WTF is causing gl.drawElements to throw INVALID_VALUE glError
    /*
    var numIndices = // top and bottom triangle fans are drawn without indices
        6 * corners; // outer faces triangle list (more efficient than tristrip in this case)
    var indices = new WebGLUnsignedShortArray(numIndices * 10);
    */
    
    function makeFace(offset, y, nx, ny, nz)
    {
        var cursor = offset;
        // center vertex
        vertices[cursor++] = 0;
        vertices[cursor++] = y;
        vertices[cursor++] = 0;
        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;
        
        for(var i = 0; i <= corners; ++i)
        {
            var theta = i * (2.0 * Math.PI / corners);
            vertices[cursor++] = radius * Math.cos(theta);
            vertices[cursor++] = y;
            vertices[cursor++] = radius * Math.sin(theta);
            vertices[cursor++] = nx;
            vertices[cursor++] = ny;
            vertices[cursor++] = nz;
        }
    }
    
    makeFace(0, 0, 0.0, -1.0, 0.0);
    makeFace((corners + 2) * floatsPerVertex, height, 0.0, 1.0, 0.0);

    var sideoffset = (2 * (corners + 2)) * floatsPerVertex;
    var cursor = sideoffset;
    for(var i = 0; i < corners; ++i)
    {
        var theta0 = i * (2.0 * Math.PI / corners)
        var theta1 = (i+1) * (2.0 * Math.PI / corners);
        var mid = (theta0 + theta1) / 2.0;
        
        var nx = Math.cos(mid);
        var ny = 0.0;
        var nz = Math.sin(mid);
        
        var x0 = radius * Math.cos(theta0);
        var z0 = radius * Math.sin(theta0);
        var x1 = radius * Math.cos(theta1);
        var z1 = radius * Math.sin(theta1);

        // vertex 0
        vertices[cursor++] = x0;
        vertices[cursor++] = height;
        vertices[cursor++] = z0;

        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;

        // vertex 1
        vertices[cursor++] = x0;
        vertices[cursor++] = 0.0;
        vertices[cursor++] = z0;
        
        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;

        // vertex 2
        vertices[cursor++] = x1;
        vertices[cursor++] = height;
        vertices[cursor++] = z1;
        
        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;

        // TODO: get rid of duplicate vertices 2 & 1 with gl.drawElements
        // vertex 2
        vertices[cursor++] = x1;
        vertices[cursor++] = height;
        vertices[cursor++] = z1;
        
        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;

        // vertex 1
        vertices[cursor++] = x0;
        vertices[cursor++] = 0.0;
        vertices[cursor++] = z0;
        
        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;

        // vertex 3
        vertices[cursor++] = x1;
        vertices[cursor++] = 0.0;
        vertices[cursor++] = z1;
        
        vertices[cursor++] = nx;
        vertices[cursor++] = ny;
        vertices[cursor++] = nz;
    }

/*    
    for(var i = 0; i < corners; ++i)
    {
        indices[i*6+0] = sideoffset + (6*i)+0;
        indices[i*6+1] = sideoffset + (6*i)+1;
        indices[i*6+2] = sideoffset + (6*i)+2;
        indices[i*6+3] = sideoffset + (6*i)+2;
        indices[i*6+4] = sideoffset + (6*i)+1;
        indices[i*6+5] = sideoffset + (6*i)+3;
    }*/

	var vbo = gl.createBuffer();
    checkWebGLError(gl);
	gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
    checkWebGLError(gl);
	gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    checkWebGLError(gl);

/*	var ibo = gl.createBuffer();
    checkWebGLError(gl);
	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
    checkWebGLError(gl);
	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    checkWebGLError(gl);*/

    
    this.draw = function(program)
    {
        var posLoc = gl.getAttribLocation(program, "position");
        checkWebGLError(gl);
        var norLoc = gl.getAttribLocation(program, "normal");
        checkWebGLError(gl);
        
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
        checkWebGLError(gl);
        gl.vertexAttribPointer(posLoc, 3, gl.FLOAT, gl.FALSE, 24, 0);
        checkWebGLError(gl);
        gl.vertexAttribPointer(norLoc, 3, gl.FLOAT, gl.FALSE, 24, 12);
        checkWebGLError(gl);
		
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
        checkWebGLError(gl);
        
        gl.enableVertexAttribArray(posLoc);
        checkWebGLError(gl);
        gl.enableVertexAttribArray(norLoc);
        checkWebGLError(gl);

        // draw top & bottom
        gl.drawArrays(gl.TRIANGLE_FAN, 0, corners+2);
        checkWebGLError(gl);
        
        gl.drawArrays(gl.TRIANGLE_FAN, corners+2, corners+2);
        checkWebGLError(gl);
        
        // draw sidewall        
        gl.drawArrays(gl.TRIANGLES, sideoffset/floatsPerVertex, 6 * corners);
        //gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);
        checkWebGLError(gl);
        
        gl.disableVertexAttribArray(posLoc);
        checkWebGLError(gl);
        gl.disableVertexAttribArray(norLoc);
        checkWebGLError(gl);
    }

	this.getHeight = function()
	{
		return height;
	}
}

function WebGLPieces(gl, num, radius)
{
    var pieceshader = new Shader(
        gl,
		"const vec4 lightpos = vec4(0.0, 10.0, 0.0, 1.0); "+
		"attribute vec3 position; attribute vec3 normal; "+
		"varying vec3 nor; varying vec4 pos; varying vec4 lightViewSpace; "+
		"uniform mat4 projection; uniform mat4 view; uniform mat4 model; "+
		"void main() {"+
		"   pos = view * model * vec4(position, 1);"+
		"   gl_Position = projection * pos;"+
		"   nor = normalize((view * model * vec4(normal, 0)).xyz);"+
		"   lightViewSpace = view * lightpos;"+
		"}"
		,
        "varying vec3 nor; varying vec4 pos; "+
		"varying vec4 lightViewSpace;" +
		"uniform vec4 color; "+
		"const vec3 attenuation  = vec3(1.0, 0.010, 0.005);"+
		"void main() {" +
		"   vec4 pos2light = lightViewSpace - pos;" + 
		"   float dist = length(pos2light);" + 
		"   vec4 light = normalize(pos2light);" +
		"   float attfactor = 1.0 / (attenuation.x + attenuation.y * dist + attenuation.z * dist * dist);"+
		"   float diffuse = attfactor * max(0.0, dot(nor, light.xyz));"+
		"   float specular = attfactor * pow(max(0.0, dot(-reflect(light.xyz, nor), normalize(-pos).xyz)), 4.0);"+
		"   gl_FragColor = vec4(((0.4 + diffuse) * color.xyz + specular * vec3(1.0, 1.0, 1.0)), 1.0);"+
		"}");

    var pieces = [];
    for(var i = 0; i < num; ++i)
        pieces.push(new WebGLPiece(gl, i+1, radius));

    this.draw = function(piece, projection, view, model, color)
    {    
        gl.useProgram(pieceshader.program);
        checkWebGLError(gl);
        
        var projLoc = gl.getUniformLocation(pieceshader.program, "projection");
        checkWebGLError(gl);
        var viewLoc = gl.getUniformLocation(pieceshader.program, "view");
        checkWebGLError(gl);
        var modelLoc = gl.getUniformLocation(pieceshader.program, "model");
        checkWebGLError(gl);
		var colorLoc = gl.getUniformLocation(pieceshader.program, "color")
		checkWebGLError(gl);
		gl.uniform4f(colorLoc, color[0], color[1], color[2], color[3]);
        checkWebGLError(gl);

        gl.uniformMatrix4fv(projLoc, true, projection);
        checkWebGLError(gl);
        gl.uniformMatrix4fv(viewLoc, true, view);
        checkWebGLError(gl);
        gl.uniformMatrix4fv(modelLoc, true, model);
        checkWebGLError(gl);
        
		if (piece < pieces.length) pieces[piece].draw(pieceshader.program);
		else pieces[pieces.length - 1].draw(pieceshader.program);
    }

	this.getNumPieces = function()
	{
		return pieces.length;
	}
	
	this.getPiece = function(piece)
	{
		if (piece < pieces.length) return pieces[piece - 1];
		else return pieces[pieces.length - 1];
	}
}
